package org.raftkv.raft.tracker;

import org.raftkv.raft.exceptions.RaftException;
import org.raftkv.raft.quorum.JointConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Set;

/**
 * Config 反映了在 ProgressTracker 中跟踪的配置
 */
public class Config implements Cloneable, Serializable {

    public static final Logger LOGGER = LoggerFactory.getLogger(Config.class);

    private JointConfig voters;

    /**
     * 如果配置是联合的，则 autoLeave 为 true，并且在可能的情况下，Raft 应自动执行到传入配置的转换。<br/>
     * 如果为 false，则配置将是联合的，直到应用程序手动启动转换。
     */
    private boolean autoLeave;

    private Set<Long> learners;

    private Set<Long> learnersNext;

    @Override
    public String toString() {
        return "Config{" +
                "voters=" + voters +
                ", autoLeave=" + autoLeave +
                ", learners=" + learners +
                ", learnersNext=" + learnersNext +
                '}';
    }

    @Override
    public Config clone() {
        ObjectOutputStream oos;
        ByteArrayOutputStream baos;
        ObjectInputStream ois;
        ByteArrayInputStream bais;

        try {
            // 序列化
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(this);
            oos.flush();
            // 反序列化
            bais = new ByteArrayInputStream(baos.toByteArray());
            ois = new ObjectInputStream(bais);
            return (Config) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            LOGGER.error("clone failed!", e);
            throw new RaftException();
        }
    }

    public JointConfig getVoters() {
        return voters;
    }

    public void setVoters(JointConfig voters) {
        this.voters = voters;
    }

    public boolean isAutoLeave() {
        return autoLeave;
    }

    public void setAutoLeave(boolean autoLeave) {
        this.autoLeave = autoLeave;
    }

    public Set<Long> getLearners() {
        return learners;
    }

    public void setLearners(Set<Long> learners) {
        this.learners = learners;
    }

    public Set<Long> getLearnersNext() {
        return learnersNext;
    }

    public void setLearnersNext(Set<Long> learnersNext) {
        this.learnersNext = learnersNext;
    }

}
